/*
 * D-Bus Java Implementation Copyright (c) 2005-2006 Matthew Johnson This
 * program is free software; you can redistribute it and/or modify it under the
 * terms of either the GNU Lesser General Public License Version 2 or the
 * Academic Free Licence Version 2.1. Full licence texts are included in the
 * COPYING file with this program.
 */
package org.freedesktop.dbus;

import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import org.freedesktop.dbus.exceptions.DBusException;

/**
 * This class is the super class of both Structs and Tuples and holds common
 * methods.
 */
abstract class Container {
  private static Map<Type, Type[]> typecache = new HashMap<Type, Type[]>();

  static Type[] getTypeCache(Type k) {
    return typecache.get(k);
  }

  static void putTypeCache(Type k, Type[] v) {
    typecache.put(k, v);
  }

  private Object[] parameters = null;

  public Container() {
  }

  @Override
  public final boolean equals(Object other) {
    if (other instanceof Container) {
      Container that = (Container) other;
      if (this.getClass().equals(that.getClass())) {
        return Arrays.equals(getParameters(), that.getParameters());
      } else {
        return false;
      }
    } else {
      return false;
    }
  }

  /**
   * Returns the struct contents in order.
   * 
   * @throws DBusException
   *           If there is a problem doing this.
   */
  public final Object[] getParameters() {
    if (null != parameters) { return parameters; }
    setup();
    return parameters;
  }

  private void setup() {
    Field[] fs = getClass().getDeclaredFields();
    Object[] args = new Object[fs.length];

    int diff = 0;
    for (Field f : fs) {
      Position p = f.getAnnotation(Position.class);
      if (null == p) {
        diff++;
        continue;
      }
      try {
        args[p.value()] = f.get(this);
      } catch (IllegalAccessException IAe) {
      }
    }

    parameters = new Object[args.length - diff];
    System.arraycopy(args, 0, parameters, 0, parameters.length);
  }

  /** Returns this struct as a string. */
  @Override
  public final String toString() {
    String s = getClass().getName() + "<";
    if (null == parameters) {
      setup();
    }
    if (0 == parameters.length) { return s + ">"; }
    for (Object o : parameters) {
      s += o + ", ";
    }
    return s.replaceAll(", $", ">");
  }
}
